package cmd

import (
	"fmt"
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
	"litter-api/app/util/pool"
	"litter-api/ctl"
	"litter-api/router"
	"net/http"
	"sync/atomic"
)

var (
	err       error
	srv       *http.Server
	createCmd = &cobra.Command{
		Use:   "run",
		Short: "launch the server",
		Long:  "launch the server",
		RunE:  run,
	}
)

func init() {
	rootCmd.AddCommand(createCmd)
}

func run(cmd *cobra.Command, args []string) error {
	logrus.WithFields(logrus.Fields{"location": "run", "method": "run"}).Info("Launching...")
	err := startServer()
	return err
}

func startServer() error {
	defer func() {
		// 优雅停止时，需要等待http server关闭、hub完成工作。
		// 不需要专门等待读、写两个泵的退出，因为在优雅退出时，首先停止了读泵的工作，然后写泵工作完成后，将连接关闭了。
		// 同时会向hub的disconnect channel发送消息，因此hub应当清理工作的最后一站
		if gracefullyStop == 1 {
			logrus.WithFields(logrus.Fields{"location": "run", "method": "startServer"}).Info("Received quit signal, waiting for http server to shutdown...")
			<-httpServerStopped
		}
	}()

	go func() {
		select {
		case <-ctl.CmdGracefullyStop:
			atomic.StoreUint32(&gracefullyStop, 1)
			close(gracefullyStopCh)
			logrus.WithFields(logrus.Fields{"location": "run", "method": "startServer"}).Info("Gracefully shutting down http server...")
			if err = stop(); err != nil {
				logrus.WithFields(logrus.Fields{"location": "run", "method": "startServer"}).Warn(err)
			}
		}
	}()

	//mysql启动
	pool.Db, err = startMysqlServer()
	if err != nil {
		return err
	}
	logrus.WithFields(logrus.Fields{"location": "run", "method": "startServer"}).Info("Mysql service startup ...")

	r := gin.Default()
	engine := router.NewRouter(r)
	// debug模式
	if logrus.GetLevel() >= logrus.DebugLevel {
		logrus.WithFields(logrus.Fields{"location": "run", "method": "startServer"}).Info("Enter debug mode")

		// 跨域中间件
		config := cors.DefaultConfig()
		config.AllowOrigins = []string{"*"}
		config.AllowHeaders = []string{"*"}
		config.ExposeHeaders = []string{"Content-Type"}
		config.AllowCredentials = true
		//config.AllowWebSockets = true
		r.Use(cors.New(config))
	}
	srv = &http.Server{
		Addr:    fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
		Handler: r,
	}
	router.Route(engine)

	err = srv.ListenAndServe()
	if err != nil {
		if !(err == http.ErrServerClosed) {
			return err
		}
	}
	return nil
}

func startMysqlServer() (*gorm.DB, error) {
	dbconf := cfg.Mysql
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", dbconf.User, dbconf.Pass, dbconf.Host, dbconf.Port, dbconf.DbName)
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true,
			TablePrefix:   dbconf.Prefix,
		},
		//Logger: newLogger, // 日志配置
	})
	if err != nil {
		return nil, err
	}
	return db, nil
}
